package com.tinyengine.it.service.vue;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tinyengine.it.common.utils.GenDir;
import com.tinyengine.it.model.entity.TPage;
import com.tinyengine.it.model.vo.vue.MenuVo;
import com.tinyengine.it.model.vo.vue.Route;
import com.tinyengine.it.service.engine.extend.TPageService;
import com.tinyengine.it.tool.TemplateVueProcessor;
import com.tinyengine.it.tool.ZipUtils;
import freemarker.template.TemplateException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * vue生成服务
 *
 * @author 刘平
 * @date 2025/04/14 11:05
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class VueGenerationService {

    /**
     * T页业务
     */
    private final TPageService tPageService;

    /**
     * 初始化项目
     *
     * @throws InterruptedException 无效
     * @throws IOException          无效
     * @author 刘平
     * @date 2025/04/14 11:06
     */
    public void initProject(Integer appId) throws InterruptedException, IOException {

        File file = new File(GenDir.getSpringOptSourcePathBasedOnOS() + FileUtil.FILE_SEPARATOR + "saber3.zip");

        String projectTargetDir = GenDir.getVueOptTargetPathBasedOnOS(appId);

        ZipUtils.deleteAllFilesInDir(projectTargetDir);

        FileUtil.mkdir(projectTargetDir);

        //将目标工程压缩包解压至目标目录
        ZipUtils.unzip(new FileInputStream(file), projectTargetDir);

        String packagePath = projectTargetDir + FileUtil.FILE_SEPARATOR + "package.json";
        String packageJsonStr = FileUtil.readString(packagePath, StandardCharsets.UTF_8);
        JSONObject jsonObj = JSON.parseObject(packageJsonStr);
        jsonObj.put("app-id", appId.toString());

        FileWriter fileWriter = FileWriter.create(new File(packagePath));
        fileWriter.write(JSON.toJSONString(jsonObj, JSONWriter.Feature.PrettyFormat));

        Thread.sleep(1000 * 2);
    }


    /**
     * 视图文件生成器
     *
     * @author 刘平
     * @date 2025/04/14 11:06
     */
    public void viewsFileGenerator(Integer appId) {
        List<TPage> pages = tPageService.list(new LambdaQueryWrapper<TPage>().eq(TPage::getIsPage, Boolean.TRUE).eq(TPage::getAppId, appId));

        pages.forEach(page -> {

            String filePath = tPageService.getPath(page.getId(), Boolean.TRUE);

            String vueContent = tPageService.generationSfcContent(page.getSfcContent());
            if (StrUtil.isBlank(vueContent)) {
                vueContent = "";
            }
            String pathDirAll = GenDir.getVueOptTargetPathBasedOnOS(appId) + FileUtil.FILE_SEPARATOR + GenDir.optTargetVueViews + filePath;
            FileUtil.mkdir(pathDirAll);
            Path path = Paths.get(pathDirAll + FileUtil.FILE_SEPARATOR + page.getName() + ".vue");
            try {
                FileUtil.touch(path.toFile());
                log.info("创建vue文件:{}", path.toFile().getAbsoluteFile());
                Files.write(path, vueContent.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    /**
     * 路由器配置生成器
     *
     * @throws IOException       无效
     * @throws TemplateException 无效
     */
    public void routerConfigGenerator(Integer project) throws IOException, TemplateException {
        List<TPage> pages = tPageService.list();

        //根目录的路由
        /*List<TPage> rootPathRouter = pages.parallelStream().filter(f -> Integer.valueOf(1).equals(f.getIsPage()) && Integer.valueOf(0).equals(f.getParentId())).collect(Collectors.toList());
        rootPathRouter.stream().forEach(page -> rootRoutes.add(new Route()
                .setName(page.getName())
                .setPath("/" + page.getName())
                .setComponent("@/views/" + page.getName() + ".vue")
                .setId(page.getId())
                .setParentId(page.getParentId()))
        );

        Map<String, Route> routeMap = rootRoutes.stream().collect(Collectors.toMap(m -> m.getPath(), m -> m));

        //根目录
        List<TPage> rootPaths = pages.parallelStream().filter(f -> Integer.valueOf(0).equals(f.getIsPage()) && Integer.valueOf(0).equals(f.getParentId())).collect(Collectors.toList());
        for (TPage rootPath : rootPaths) {
            routeMap.put("/" + rootPath.getRoute(), new Route()
                    .setPath("/" + rootPath.getRoute())
                    .setName(rootPath.getName())
            );
        }

        //非根目录路由
        List<TPage> pathFiles = pages.parallelStream()
                .filter(page -> rootPathRouter.stream()
                        .noneMatch(excludedPage -> excludedPage.getId() == page.getId()))  // 检查是否在排除列表中
                .collect(Collectors.toList());

        for (TPage page : pathFiles) {
            if (Integer.valueOf(1).equals(page.getIsPage())) {
                String vuePath = tPageService.getPath(page.getId(), Boolean.TRUE);

                Map.Entry<String, Route> filterRouteEntry = routeMap.entrySet().stream().filter(f -> vuePath.startsWith(f.getKey())).findFirst().orElse(null);
                if (ObjUtil.isNull(filterRouteEntry)) {
                    String path = vuePath + "/" + page.getName();
                    Route route = new Route()
                            .setName(page.getName())
                            .setPath(path.replaceFirst("^" + filterRouteEntry.getKey(), "").replaceFirst("^/", ""))
                            .setComponent("@/views" + path + ".vue")
                            .setId(page.getId())
                            .setParentId(page.getParentId());
                    routeMap.put(vuePath, route);
                } else {
                    Route parentRouter = filterRouteEntry.getValue();
                    String path = vuePath + "/" + page.getName();
                    Route route = new Route()
                            .setName(page.getName())
                            .setPath(path.replaceFirst("^" + filterRouteEntry.getKey(), "").replaceFirst("^/", ""))
                            .setComponent("@/views" + path + ".vue")
                            .setId(page.getId())
                            .setParentId(page.getParentId());
                    List<Route> children = parentRouter.getChildren();
                    if (ObjUtil.isNull(children)) {
                        parentRouter.setChildren(new ArrayList<>());
                    }
                    parentRouter.getChildren().add(route);
                }
            }
        }*/

        List<Route> routes = BeanUtil.copyToList(pages, Route.class);

        List<Route> routeTree = buildRouteTree(routes);
        // 创建数据模型
        Map<String, Object> data = new HashMap<>();
        data.put("routes", routeTree);

        // 输出到文件
        File outFile = FileUtil.touch(GenDir.getVueOptTargetPathBasedOnOS(project) + FileUtil.FILE_SEPARATOR + GenDir.optTargetVueRouter + "views" + FileUtil.FILE_SEPARATOR + "index.js");
        TemplateVueProcessor.processTemplate("router.js.ftl", data, outFile);
        log.info("路由配置文件生成完成！");
    }

    // 构建 Route 树
    public List<Route> buildRouteTree(List<Route> routes) {
        Map<Integer, Route> map = routes.stream().collect(Collectors.toMap(Route::getId, r -> r));
        List<Route> roots = new ArrayList<>();
        for (Route route : routes) {
            if (route.getParentId() == 0) {
                route.setPath("/" + route.getName());
                if (Integer.valueOf(1).equals(route.getIsPage())) {
                    route.setComponent("@/views/" + route.getName() + ".vue");
                }
                route.setVuePath("/" + route.getName());
                route.setMenuParentId(0L);
                roots.add(route);
            } else {
                Route parent = map.get(route.getParentId());
                if (parent != null) {
                    List<Route> children = parent.getChildren();
                    if (ObjUtil.isNull(children)) {
                        parent.setChildren(new ArrayList<>());
                    }

                    String vuePathParent = tPageService.getPath(route.getId(), Boolean.TRUE);
                    String path = vuePathParent + "/" + route.getName();

                    //Route parentRoute = routes.stream().filter(f -> f.getId().equals(route.getParentId())).findFirst().get();
                    route.setPath(path.replaceFirst("^" + vuePathParent, "").replaceFirst("^/", ""));
                    if (Integer.valueOf(1).equals(route.getIsPage())) {
                        route.setComponent("@/views" + path + ".vue");
                    }
                    route.setVuePath(path);
                    route.setMenuParentId(parent.getMenuId());
                    parent.getChildren().add(route);
                }
            }
        }
        return roots;
    }

    public List<MenuVo> printRouteList(List<Route> routes) {
        if (routes == null || routes.isEmpty()) {
            return CollUtil.newArrayList();
        }
        List<MenuVo> menuVos = new ArrayList<>();
        List<Route> rootRouter = routes.stream().filter(f -> Integer.valueOf(0).equals(f.getParentId())).collect(Collectors.toList());

        for (Route route : rootRouter) {
            printRouteTree(route, null, 0, menuVos);
        }
        return menuVos;
    }

    private void printRouteTree(Route route, Route parent, int level, List<MenuVo> menuVos) {
        if (route == null) {
            return;
        }
        // 根据层级打印缩进
        //String indent = "  ".repeat(level);
        //System.out.printf("%s- [%s] %s (isPage=%d)\n", indent, route.getPath(), route.getName(), route.getIsPage());
        MenuVo menu = new MenuVo()
                .setId(route.getMenuId())
                .setParentId(ObjUtil.isNull(parent) ? 0 : parent.getMenuId())
                .setCode(route.getCode())
                .setName(route.getName())
                .setAlias("menu")
                .setPath(route.getVuePath())
                .setSort(0)
                .setCategory(1)
                .setAction(0)
                .setIsOpen(1)
                .setIsDeleted(0)
                .setComponent("");
        menuVos.add(menu);
        // 如果有子节点，递归遍历子节点
        if (route.getChildren() != null && !route.getChildren().isEmpty()) {
            for (Route child : route.getChildren()) {
                printRouteTree(child, route, level + 1, menuVos);
            }
        }
    }
}
